home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2004 #11 / Amiga Plus CD - 2004 - No. 11.iso / AmiSoft / Comm / www / tidy_os4.lha / tidy / src / streamio.c < prev    next >
C/C++ Source or Header  |  2004-07-25  |  34KB  |  1,319 lines

  1. /* streamio.c -- handles character stream I/O
  2.  
  3.   (c) 1998-2004 (W3C) MIT, ERCIM, Keio University
  4.   See tidy.h for the copyright notice.
  5.  
  6.   CVS Info :
  7.  
  8.     $Author: hoehrmann $ 
  9.     $Date: 2004/03/07 14:38:47 $ 
  10.     $Revision: 1.23 $ 
  11.  
  12.   Wrapper around Tidy input source and output sink
  13.   that calls appropriate interfaces, and applies
  14.   necessary char encoding transformations: to/from
  15.   ISO-10646 and/or UTF-8.
  16.  
  17. */
  18.  
  19. #include <stdio.h>
  20. #include <errno.h>
  21.  
  22. #include "streamio.h"
  23. #include "tidy-int.h"
  24. #include "lexer.h"
  25. #include "message.h"
  26. #include "utf8.h"
  27.  
  28. #ifdef TIDY_WIN32_MLANG_SUPPORT
  29. #include "win32tc.h"
  30. #endif
  31.  
  32. /************************
  33. ** Forward Declarations
  34. ************************/
  35.  
  36. uint ReadCharFromStream( StreamIn* in );
  37.  
  38. uint ReadByte( StreamIn* in );
  39. Bool IsEOF( StreamIn* in );
  40. void UngetByte( StreamIn* in, uint byteValue );
  41.  
  42. void PutByte( uint byteValue, StreamOut* out );
  43.  
  44. void EncodeWin1252( uint c, StreamOut* out );
  45. void EncodeMacRoman( uint c, StreamOut* out );
  46. void EncodeIbm858( uint c, StreamOut* out );
  47. void EncodeLatin0( uint c, StreamOut* out );
  48.  
  49. void outcUTF8Bytes( StreamOut *out, byte* buf, int* count );
  50. void outBOM( StreamOut *out );
  51.  
  52. /******************************
  53. ** Static (duration) Globals
  54. ******************************/
  55.  
  56. static StreamOut stderrStreamOut = 
  57. {
  58.     ASCII,
  59.     FSM_ASCII,
  60.     DEFAULT_NL_CONFIG,
  61. #ifdef TIDY_WIN32_MLANG_SUPPORT
  62.     (ulong)NULL,
  63. #endif
  64.     FileIO,
  65.     { 0, filesink_putByte }
  66. };
  67.  
  68. static StreamOut stdoutStreamOut = 
  69. {
  70.     ASCII,
  71.     FSM_ASCII,
  72.     DEFAULT_NL_CONFIG,
  73. #ifdef TIDY_WIN32_MLANG_SUPPORT
  74.     (ulong)NULL,
  75. #endif
  76.     FileIO,
  77.     { 0, filesink_putByte }
  78. };
  79.  
  80. StreamOut* StdErrOutput(void)
  81. {
  82.   if ( stderrStreamOut.sink.sinkData == 0 )
  83.       stderrStreamOut.sink.sinkData = (ulong) stderr;
  84.   return &stderrStreamOut;
  85. }
  86.  
  87. StreamOut* StdOutOutput(void)
  88. {
  89.   if ( stdoutStreamOut.sink.sinkData == 0 )
  90.       stdoutStreamOut.sink.sinkData = (ulong) stdout;
  91.   return &stdoutStreamOut;
  92. }
  93.  
  94. void  ReleaseStreamOut( StreamOut* out )
  95. {
  96.     if ( out && out != &stderrStreamOut && out != &stdoutStreamOut )
  97.     {
  98.         if ( out->iotype == FileIO )
  99.             fclose( (FILE*) out->sink.sinkData );
  100.         MemFree( out );
  101.     }
  102. }
  103.  
  104.  
  105. /************************
  106. ** Source
  107. ************************/
  108.  
  109. static StreamIn* initStreamIn( TidyDocImpl* doc, int encoding )
  110. {
  111.     StreamIn *in = (StreamIn*) MemAlloc( sizeof(StreamIn) );
  112.  
  113.     ClearMemory( in, sizeof(StreamIn) );
  114.     in->curline = 1;
  115.     in->curcol = 1;
  116.     in->encoding = encoding;
  117.     in->state = FSM_ASCII;
  118.     in->doc = doc;
  119.     in->bufsize = CHARBUF_SIZE;
  120.     in->charbuf = MemAlloc(sizeof(tchar) * in->bufsize);
  121. #ifdef TIDY_STORE_ORIGINAL_TEXT
  122.     in->otextbuf = NULL;
  123.     in->otextlen = 0;
  124.     in->otextsize = 0;
  125. #endif
  126.     return in;
  127. }
  128.  
  129. void freeStreamIn(StreamIn* in)
  130. {
  131. #ifdef TIDY_STORE_ORIGINAL_TEXT
  132.     if (in->otextbuf)
  133.         MemFree(in->otextbuf);
  134. #endif
  135.     MemFree(in->charbuf);
  136.     MemFree(in);
  137. }
  138.  
  139. StreamIn* FileInput( TidyDocImpl* doc, FILE *fp, int encoding )
  140. {
  141.     StreamIn *in = initStreamIn( doc, encoding );
  142.     initFileSource( &in->source, fp );
  143.     in->iotype = FileIO;
  144.     return in;
  145. }
  146.  
  147. StreamIn* BufferInput( TidyDocImpl* doc, TidyBuffer* buf, int encoding )
  148. {
  149.     StreamIn *in = initStreamIn( doc, encoding );
  150.     initInputBuffer( &in->source, buf );
  151.     in->iotype = BufferIO;
  152.     return in;
  153. }
  154.  
  155. StreamIn* UserInput( TidyDocImpl* doc, TidyInputSource* source, int encoding )
  156. {
  157.     StreamIn *in = initStreamIn( doc, encoding );
  158.     memcpy( &in->source, source, sizeof(TidyInputSource) );
  159.     in->iotype = UserIO;
  160.     return in;
  161. }
  162.  
  163. int ReadBOMEncoding(StreamIn *in)
  164. {
  165.     uint c, c1;
  166. #if SUPPORT_UTF16_ENCODINGS
  167.     uint bom;
  168. #endif
  169.  
  170.     c = ReadByte(in);
  171.     if (c == EndOfStream)
  172.         return -1;
  173.  
  174.     c1 = ReadByte( in );
  175.     if (c1 == EndOfStream)
  176.     {
  177.         UngetByte(in, c);
  178.         return -1;
  179.     }
  180.  
  181.     /* todo: dont warn about mismatch for auto input encoding */
  182.     /* todo: let the user override the encoding found here */
  183.  
  184. #if SUPPORT_UTF16_ENCODINGS
  185.     bom = (c << 8) + c1;
  186.  
  187.     if ( bom == UNICODE_BOM_BE )
  188.     {
  189.         /* big-endian UTF-16 */
  190.         if ( in->encoding != UTF16 && in->encoding != UTF16BE )
  191.             ReportEncodingWarning(in->doc, ENCODING_MISMATCH, UTF16BE);
  192.  
  193.         return UTF16BE; /* return decoded BOM */
  194.     }
  195.     else if (bom == UNICODE_BOM_LE)
  196.     {
  197.         /* little-endian UTF-16 */
  198.         if (in->encoding != UTF16 && in->encoding != UTF16LE)
  199.             ReportEncodingWarning(in->doc, ENCODING_MISMATCH, UTF16LE);
  200.  
  201.         return UTF16LE; /* return decoded BOM */
  202.     }
  203.     else
  204. #endif /* SUPPORT_UTF16_ENCODINGS */
  205.     {
  206.         uint c2 = ReadByte(in);
  207.  
  208.         if (c2 == EndOfStream)
  209.         {
  210.             UngetByte(in, c1);
  211.             UngetByte(in, c);
  212.             return -1;
  213.         }
  214.  
  215.         if (((c << 16) + (c1 << 8) + c2) == UNICODE_BOM_UTF8)
  216.         {
  217.             /* UTF-8 */
  218.             if (in->encoding != UTF8)
  219.                 ReportEncodingWarning(in->doc, ENCODING_MISMATCH, UTF8);
  220.  
  221.             return UTF8;
  222.         }
  223.         else
  224.             UngetByte( in, c2 );
  225.     }
  226.  
  227.     UngetByte(in, c1);
  228.     UngetByte(in, c);
  229.  
  230.     return -1;
  231. }
  232.  
  233. #ifdef TIDY_STORE_ORIGINAL_TEXT
  234. void AddByteToOriginalText(StreamIn *in, tmbchar c)
  235. {
  236.     if (in->otextlen + 1 >= in->otextsize)
  237.     {
  238.         size_t size = in->otextsize ? 1 : 2;
  239.         in->otextbuf = MemRealloc(in->otextbuf, in->otextsize + size);
  240.         in->otextsize += size;
  241.     }
  242.     in->otextbuf[in->otextlen++] = c;
  243.     in->otextbuf[in->otextlen  ] = 0;
  244. }
  245.  
  246. void AddCharToOriginalText(StreamIn *in, tchar c)
  247. {
  248.     int i, err, count = 0;
  249.     tmbchar buf[10] = {0};
  250.     
  251.     err = EncodeCharToUTF8Bytes(c, buf, NULL, &count);
  252.  
  253.     if (err)
  254.     {
  255.         /* replacement character 0xFFFD encoded as UTF-8 */
  256.         buf[0] = (byte) 0xEF;
  257.         buf[1] = (byte) 0xBF;
  258.         buf[2] = (byte) 0xBD;
  259.         count = 3;
  260.     }
  261.     
  262.     for (i = 0; i < count; ++i)
  263.         AddByteToOriginalText(in, buf[i]);
  264. }
  265. #endif
  266.  
  267.  
  268. uint ReadChar( StreamIn *in )
  269. {
  270.     uint c = EndOfStream;
  271.     uint tabsize = cfg( in->doc, TidyTabSize );
  272. #ifdef TIDY_STORE_ORIGINAL_TEXT
  273.     Bool added = no;
  274. #endif
  275.  
  276.     if ( in->pushed )
  277.         return PopChar( in );
  278.  
  279.     in->lastcol = in->curcol;
  280.  
  281.     if ( in->tabs > 0 )
  282.     {
  283.         in->curcol++;
  284.         in->tabs--;
  285.         return ' ';
  286.     }
  287.     
  288.     for (;;)
  289.     {
  290.         c = ReadCharFromStream(in);
  291.  
  292.         if ( EndOfStream == c )
  293.             return EndOfStream;
  294.  
  295.         if (c == '\n')
  296.         {
  297. #ifdef TIDY_STORE_ORIGINAL_TEXT
  298.             added = yes;
  299.             AddCharToOriginalText(in, (tchar)c);
  300. #endif
  301.             in->curcol = 1;
  302.             in->curline++;
  303.             break;
  304.         }
  305.  
  306.         if (c == '\t')
  307.         {
  308. #ifdef TIDY_STORE_ORIGINAL_TEXT
  309.             added = yes;
  310.             AddCharToOriginalText(in, (tchar)c);
  311. #endif
  312.             in->tabs = tabsize - ((in->curcol - 1) % tabsize) - 1;
  313.             in->curcol++;
  314.             c = ' ';
  315.             break;
  316.         }
  317.  
  318.         /* #427663 - map '\r' to '\n' - Andy Quick 11 Aug 00 */
  319.         if (c == '\r')
  320.         {
  321. #ifdef TIDY_STORE_ORIGINAL_TEXT
  322.             added = yes;
  323.             AddCharToOriginalText(in, (tchar)c);
  324. #endif
  325.             c = ReadCharFromStream(in);
  326.             if (c != '\n')
  327.             {
  328.                 UngetChar( c, in );
  329.                 c = '\n';
  330.             }
  331.             else
  332.             {
  333. #ifdef TIDY_STORE_ORIGINAL_TEXT
  334.                 AddCharToOriginalText(in, (tchar)c);
  335. #endif
  336.             }
  337.             in->curcol = 1;
  338.             in->curline++;
  339.             break;
  340.         }
  341.  
  342. #ifndef NO_NATIVE_ISO2022_SUPPORT
  343.         /* strip control characters, except for Esc */
  344.         if (c == '\033')
  345.             break;
  346. #endif
  347.  
  348.         /* Form Feed is allowed in HTML */
  349.         if ( c == '\015' && !cfgBool(in->doc, TidyXmlTags) )
  350.             break;
  351.             
  352.         if ( c < 32 )
  353.             continue; /* discard control char */
  354.  
  355.         /* watch out for chars that have already been decoded such as */
  356.         /* IS02022, UTF-8 etc, that don't require further decoding */
  357.  
  358.         if (
  359.             in->encoding == RAW
  360. #ifndef NO_NATIVE_ISO2022_SUPPORT
  361.          || in->encoding == ISO2022
  362. #endif
  363.          || in->encoding == UTF8
  364.  
  365. #if SUPPORT_ASIAN_ENCODINGS
  366.          || in->encoding == SHIFTJIS /* #431953 - RJ */
  367.          || in->encoding == BIG5     /* #431953 - RJ */
  368. #endif
  369.            )
  370.         {
  371.             in->curcol++;
  372.             break;
  373.         }
  374.  
  375. #if SUPPORT_UTF16_ENCODINGS
  376.         /* handle surrogate pairs */
  377.         if ( in->encoding == UTF16LE ||
  378.              in->encoding == UTF16   ||
  379.              in->encoding == UTF16BE )
  380.         {
  381.             if ( !IsValidUTF16FromUCS4(c) )
  382.             {
  383.                 /* invalid UTF-16 value */
  384.                 ReportEncodingError(in->doc, INVALID_UTF16, c, yes);
  385.                 c = 0;
  386.             }
  387.             else if ( IsLowSurrogate(c) )
  388.             {
  389.                 uint n = c;
  390.                 uint m = ReadCharFromStream( in );
  391.                 if ( m == EndOfStream )
  392.                    return EndOfStream;
  393.  
  394.                 c = 0;
  395.                 if ( IsHighSurrogate(m) )
  396.                 {
  397.                     n = CombineSurrogatePair( m, n );
  398.                     if ( IsValidCombinedChar(n) )
  399.                         c = n;
  400.                 }
  401.                 /* not a valid pair */
  402.                 if ( 0 == c )
  403.                     ReportEncodingError( in->doc, INVALID_UTF16, c, yes );
  404.             }
  405.         }
  406. #endif
  407.  
  408.         /* Do first: acts on range 128 - 255 */
  409.         switch ( in->encoding )
  410.         {
  411.         case MACROMAN:
  412.             c = DecodeMacRoman( c );
  413.             break;
  414.         case IBM858:
  415.             c = DecodeIbm850( c );
  416.             break;
  417.         case LATIN0:
  418.             c = DecodeLatin0( c );
  419.             break;
  420.         }
  421.  
  422.         /* produced e.g. as a side-effect of smart quotes in Word */
  423.         /* but can't happen if using MACROMAN encoding */
  424.         if ( 127 < c && c < 160 )
  425.         {
  426.             uint c1 = 0, replMode = DISCARDED_CHAR;
  427.             Bool isVendorChar = ( in->encoding == WIN1252 ||
  428.                                   in->encoding == MACROMAN );
  429.             Bool isWinChar    = ( in->encoding == WIN1252 ||
  430.                                   ReplacementCharEncoding == WIN1252 );
  431.             Bool isMacChar    = ( in->encoding == MACROMAN ||
  432.                                   ReplacementCharEncoding == MACROMAN );
  433.             
  434.             /* set error position just before offending character */
  435.             in->doc->lexer->lines = in->curline;
  436.             in->doc->lexer->columns = in->curcol;
  437.                 
  438.             if ( isWinChar )
  439.                 c1 = DecodeWin1252( c );
  440.             else if ( isMacChar )
  441.                 c1 = DecodeMacRoman( c );
  442.             if ( c1 )
  443.                 replMode = REPLACED_CHAR;
  444.                 
  445.             if ( c1 == 0 && isVendorChar )
  446.                 ReportEncodingError(in->doc, VENDOR_SPECIFIC_CHARS, c, replMode == DISCARDED_CHAR);
  447.             else if ( ! isVendorChar )
  448.                 ReportEncodingError(in->doc, INVALID_SGML_CHARS, c, replMode == DISCARDED_CHAR);
  449.                 
  450.             c = c1;
  451.         }
  452.  
  453.         if ( c == 0 )
  454.             continue; /* illegal char is discarded */
  455.         
  456.         in->curcol++;
  457.         break;
  458.     }
  459.  
  460. #ifdef TIDY_STORE_ORIGINAL_TEXT
  461.     if (!added)
  462.         AddCharToOriginalText(in, (tchar)c);
  463. #endif
  464.  
  465.     return c;
  466. }
  467.  
  468. uint PopChar( StreamIn *in )
  469. {
  470.     uint c = EndOfStream;
  471.     if ( in->pushed )
  472.     {
  473.         assert( in->bufpos > 0 );
  474.         c = in->charbuf[ --in->bufpos ];
  475.         if ( in->bufpos == 0 )
  476.             in->pushed = no;
  477.  
  478.         if ( c == '\n' )
  479.         {
  480.             in->curcol = 1;
  481.             in->curline++;
  482.             return c;
  483.         }
  484.         in->curcol++;
  485.     }
  486.     return c;
  487. }
  488.  
  489. void UngetChar( uint c, StreamIn *in )
  490. {
  491.     if (c == EndOfStream)
  492.     {
  493.         /* fprintf(stderr, "Attempt to UngetChar EOF\n"); */
  494.         return;
  495.     }
  496.     
  497.     in->pushed = yes;
  498.  
  499.     if (in->bufpos + 1 >= in->bufsize)
  500.         in->charbuf = MemRealloc(in->charbuf, sizeof(tchar) * ++(in->bufsize));
  501.  
  502.     in->charbuf[(in->bufpos)++] = c;
  503.  
  504.     if (c == '\n')
  505.         --(in->curline);
  506.  
  507.     in->curcol = in->lastcol;
  508. }
  509.  
  510.  
  511.  
  512. /************************
  513. ** Sink
  514. ************************/
  515.  
  516. static StreamOut* initStreamOut( int encoding, uint nl )
  517. {
  518.     StreamOut* out = (StreamOut*) MemAlloc( sizeof(StreamOut) );
  519.     ClearMemory( out, sizeof(StreamOut) );
  520.     out->encoding = encoding;
  521.     out->state = FSM_ASCII;
  522.     out->nl = nl;
  523.     return out;
  524. }
  525.  
  526. StreamOut* FileOutput( FILE* fp, int encoding, uint nl )
  527. {
  528.     StreamOut* out = initStreamOut( encoding, nl );
  529.     initFileSink( &out->sink, fp );
  530.     out->iotype = FileIO;
  531.     return out;
  532. }
  533. StreamOut* BufferOutput( TidyBuffer* buf, int encoding, uint nl )
  534. {
  535.     StreamOut* out = initStreamOut( encoding, nl );
  536.     initOutputBuffer( &out->sink, buf );
  537.     out->iotype = BufferIO;
  538.     return out;
  539. }
  540. StreamOut* UserOutput( TidyOutputSink* sink, int encoding, uint nl )
  541. {
  542.     StreamOut* out = initStreamOut( encoding, nl );
  543.     memcpy( &out->sink, sink, sizeof(TidyOutputSink) );
  544.     out->iotype = UserIO;
  545.     return out;
  546. }
  547.  
  548. void WriteChar( uint c, StreamOut* out )
  549. {
  550.     /* Translate outgoing newlines */
  551.     if ( LF == c )
  552.     {
  553.       if ( out->nl == TidyCRLF )
  554.           WriteChar( CR, out );
  555.       else if ( out->nl == TidyCR )
  556.           c = CR;
  557.     }
  558.  
  559.     if (out->encoding == MACROMAN)
  560.     {
  561.         EncodeMacRoman( c, out );
  562.     }
  563.     else if (out->encoding == WIN1252)
  564.     {
  565.         EncodeWin1252( c, out );
  566.     }
  567.     else if (out->encoding == IBM858)
  568.     {
  569.         EncodeIbm858( c, out );
  570.     }
  571.     else if (out->encoding == LATIN0)
  572.     {
  573.         EncodeLatin0( c, out );
  574.     }
  575.  
  576.     else if (out->encoding == UTF8)
  577.     {
  578.         int count = 0;
  579.         
  580.         EncodeCharToUTF8Bytes( c, NULL, &out->sink, &count );
  581.         if (count <= 0)
  582.         {
  583.           /* ReportEncodingError(in->lexer, INVALID_UTF8 | REPLACED_CHAR, c); */
  584.             /* replacement char 0xFFFD encoded as UTF-8 */
  585.             PutByte(0xEF, out); PutByte(0xBF, out); PutByte(0xBF, out);
  586.         }
  587.     }
  588. #ifndef NO_NATIVE_ISO2022_SUPPORT
  589.     else if (out->encoding == ISO2022)
  590.     {
  591.         if (c == 0x1b)  /* ESC */
  592.             out->state = FSM_ESC;
  593.         else
  594.         {
  595.             switch (out->state)
  596.             {
  597.             case FSM_ESC:
  598.                 if (c == '$')
  599.                     out->state = FSM_ESCD;
  600.                 else if (c == '(')
  601.                     out->state = FSM_ESCP;
  602.                 else
  603.                     out->state = FSM_ASCII;
  604.                 break;
  605.  
  606.             case FSM_ESCD:
  607.                 if (c == '(')
  608.                     out->state = FSM_ESCDP;
  609.                 else
  610.                     out->state = FSM_NONASCII;
  611.                 break;
  612.  
  613.             case FSM_ESCDP:
  614.                 out->state = FSM_NONASCII;
  615.                 break;
  616.  
  617.             case FSM_ESCP:
  618.                 out->state = FSM_ASCII;
  619.                 break;
  620.  
  621.             case FSM_NONASCII:
  622.                 c &= 0x7F;
  623.                 break;
  624.             }
  625.         }
  626.  
  627.         PutByte(c, out);
  628.     }
  629. #endif /* NO_NATIVE_ISO2022_SUPPORT */
  630.  
  631. #if SUPPORT_UTF16_ENCODINGS
  632.     else if ( out->encoding == UTF16LE ||
  633.               out->encoding == UTF16BE ||
  634.               out->encoding == UTF16 )
  635.     {
  636.         int i, numChars = 1;
  637.         uint theChars[2];
  638.         
  639.         if ( !IsValidUTF16FromUCS4(c) )
  640.         {
  641.             /* invalid UTF-16 value */
  642.             /* ReportEncodingError(in->lexer, INVALID_UTF16 | DISCARDED_CHAR, c); */
  643.             c = 0;
  644.             numChars = 0;
  645.         }
  646.         else if ( IsCombinedChar(c) )
  647.         {
  648.             /* output both, unless something goes wrong */
  649.             numChars = 2;
  650.             if ( !SplitSurrogatePair(c, &theChars[0], &theChars[1]) )
  651.             {
  652.                 /* ReportEncodingError(in->lexer, INVALID_UTF16 | DISCARDED_CHAR, c); */
  653.                 c = 0;
  654.                 numChars = 0;
  655.             }
  656.         }
  657.         else
  658.         {
  659.             /* just put the char out */
  660.             theChars[0] = c;
  661.         }
  662.         
  663.         for (i = 0; i < numChars; i++)
  664.         {
  665.             c = theChars[i];
  666.             
  667.             if (out->encoding == UTF16LE)
  668.             {
  669.                 uint ch = c & 0xFF; PutByte(ch, out); 
  670.                 ch = (c >> 8) & 0xFF; PutByte(ch, out); 
  671.             }
  672.     
  673.             else if (out->encoding == UTF16BE || out->encoding == UTF16)
  674.             {
  675.                 uint ch = (c >> 8) & 0xFF; PutByte(ch, out); 
  676.                 ch = c & 0xFF; PutByte(ch, out); 
  677.             }
  678.         }
  679.     }
  680. #endif
  681.  
  682. #if SUPPORT_ASIAN_ENCODINGS
  683.     else if (out->encoding == BIG5 || out->encoding == SHIFTJIS)
  684.     {
  685.         if (c < 128)
  686.             PutByte(c, out);
  687.         else
  688.         {
  689.             uint ch = (c >> 8) & 0xFF; PutByte(ch, out); 
  690.             ch = c & 0xFF; PutByte(ch, out); 
  691.         }
  692.     }
  693. #endif
  694.  
  695.     else
  696.         PutByte( c, out );
  697. }
  698.  
  699.  
  700.  
  701. /****************************
  702. ** Miscellaneous / Helpers
  703. ****************************/
  704.  
  705. /* char encoding used when replacing illegal SGML chars,
  706. ** regardless of specified encoding.  Set at compile time
  707. ** to either Windows or Mac.
  708. */
  709. const int ReplacementCharEncoding = DFLT_REPL_CHARENC;
  710.  
  711.  
  712. /* Mapping for Windows Western character set CP 1252 
  713. ** (chars 128-159/U+0080-U+009F) to Unicode.
  714. */
  715. static const uint Win2Unicode[32] =
  716. {
  717.     0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
  718.     0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x017D, 0x0000,
  719.     0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
  720.     0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x017E, 0x0178
  721. };
  722.  
  723. /* Function for conversion from Windows-1252 to Unicode */
  724. uint DecodeWin1252(uint c)
  725. {
  726.     if (127 < c && c < 160)
  727.         c = Win2Unicode[c - 128];
  728.         
  729.     return c;
  730. }
  731.  
  732. void EncodeWin1252( uint c, StreamOut* out )
  733. {
  734.     if (c < 128 || (c > 159 && c < 256))
  735.         PutByte(c, out);
  736.     else
  737.     {
  738.         int i;
  739.  
  740.         for (i = 128; i < 160; i++)
  741.             if (Win2Unicode[i - 128] == c)
  742.             {
  743.                 PutByte(i, out);
  744.                 break;
  745.             }
  746.     }
  747. }
  748.  
  749. /*
  750.    John Love-Jensen contributed this table for mapping MacRoman
  751.    character set to Unicode
  752. */
  753.  
  754. /* modified to only need chars 128-255/U+0080-U+00FF - Terry Teague 19 Aug 01 */
  755. static const uint Mac2Unicode[128] = 
  756. {
  757.     /* x7F = DEL */
  758.     
  759.     0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
  760.     0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
  761.  
  762.     0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
  763.     0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
  764.  
  765.     0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
  766.     0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8,
  767.  
  768.     0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211,
  769.                                             /* =BD U+2126 OHM SIGN */
  770.     0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8,
  771.  
  772.     0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
  773.     0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153,
  774.  
  775.     0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
  776.                             /* =DB U+00A4 CURRENCY SIGN */
  777.     0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02,
  778.  
  779.     0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1,
  780.     0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4,
  781.     /* xF0 = Apple Logo */
  782.     /* =F0 U+2665 BLACK HEART SUIT */
  783.     0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC,
  784.     0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7
  785. };
  786.  
  787. /* Function to convert from MacRoman to Unicode */
  788. uint DecodeMacRoman(uint c)
  789. {
  790.     if (127 < c)
  791.         c = Mac2Unicode[c - 128];
  792.     return c;
  793. }
  794.  
  795. void EncodeMacRoman( uint c, StreamOut* out )
  796. {
  797.         if (c < 128)
  798.             PutByte(c, out);
  799.         else
  800.         {
  801.             /* For mac users, map Unicode back to MacRoman. */
  802.             int i;
  803.             for (i = 128; i < 256; i++)
  804.             {
  805.                 if (Mac2Unicode[i - 128] == c)
  806.                 {
  807.                     PutByte(i, out);
  808.                     break;
  809.                 }
  810.             }
  811.         }
  812. }
  813.  
  814. /* Mapping for OS/2 Western character set CP 850
  815. ** (chars 128-255) to Unicode.
  816. */
  817. const uint IBM2Unicode[128] =
  818. {
  819.     0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
  820.     0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
  821.     0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
  822.     0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
  823.     0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
  824.     0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
  825.     0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0,
  826.     0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
  827.     0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3,
  828.     0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x00a4,
  829.     0x00f0, 0x00d0, 0x00ca, 0x00cb, 0x00c8, 0x20AC, 0x00cd, 0x00ce,
  830.     0x00cf, 0x2518, 0x250c, 0x2588, 0x2584, 0x00a6, 0x00cc, 0x2580,
  831.     0x00d3, 0x00df, 0x00d4, 0x00d2, 0x00f5, 0x00d5, 0x00b5, 0x00fe,
  832.     0x00de, 0x00da, 0x00db, 0x00d9, 0x00fd, 0x00dd, 0x00af, 0x00b4,
  833.     0x00ad, 0x00b1, 0x2017, 0x00be, 0x00b6, 0x00a7, 0x00f7, 0x00b8,
  834.     0x00b0, 0x00a8, 0x00b7, 0x00b9, 0x00b3, 0x00b2, 0x25a0, 0x00a0
  835. };
  836.  
  837. /* Function for conversion from OS/2-850 to Unicode */
  838. uint DecodeIbm850(uint c)
  839. {
  840.     if (127 < c && c < 256)
  841.         c = IBM2Unicode[c - 128];
  842.  
  843.     return c;
  844. }
  845.  
  846. /* For OS/2,Java users, map Unicode back to IBM858 (IBM850+Euro). */
  847. void EncodeIbm858( uint c, StreamOut* out )
  848. {
  849.     if (c < 128)
  850.         PutByte(c, out);
  851.     else
  852.     {
  853.         int i;
  854.         for (i = 128; i < 256; i++)
  855.         {
  856.             if (IBM2Unicode[i - 128] == c)
  857.             {
  858.                 PutByte(i, out);
  859.                 break;
  860.             }
  861.         }
  862.     }
  863. }
  864.  
  865.  
  866. /* Convert from Latin0 (aka Latin9, ISO-8859-15) to Unicode */
  867. uint DecodeLatin0(uint c)
  868. {
  869.     if (159 < c && c < 191)
  870.     {
  871.         switch (c)
  872.         {
  873.         case 0xA4: c = 0x20AC; break;
  874.         case 0xA6: c = 0x0160; break;
  875.         case 0xA8: c = 0x0161; break;
  876.         case 0xB4: c = 0x017D; break;
  877.         case 0xB8: c = 0x017E; break;
  878.         case 0xBC: c = 0x0152; break;
  879.         case 0xBD: c = 0x0153; break;
  880.         case 0xBE: c = 0x0178; break;
  881.         }
  882.     }
  883.     return c;
  884. }
  885.  
  886. /* Map Unicode back to ISO-8859-15. */
  887. void EncodeLatin0( uint c, StreamOut* out )
  888. {
  889.     switch (c)
  890.     {
  891.     case 0x20AC: c = 0xA4; break;
  892.     case 0x0160: c = 0xA6; break;
  893.     case 0x0161: c = 0xA8; break;
  894.     case 0x017D: c = 0xB4; break;
  895.     case 0x017E: c = 0xB8; break;
  896.     case 0x0152: c = 0xBC; break;
  897.     case 0x0153: c = 0xBD; break;
  898.     case 0x0178: c = 0xBE; break;
  899.     }
  900.     PutByte(c, out);
  901. }
  902.  
  903. /*
  904.    Table to map symbol font characters to Unicode; undefined
  905.    characters are mapped to 0x0000 and characters without any
  906.    Unicode equivalent are mapped to '?'. Is this appropriate?
  907. */
  908.  
  909. static const uint Symbol2Unicode[] = 
  910. {
  911.     0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007,
  912.     0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E, 0x000F,
  913.     
  914.     0x0010, 0x0011, 0x0012, 0x0013, 0x0014, 0x0015, 0x0016, 0x0017,
  915.     0x0018, 0x0019, 0x001A, 0x001B, 0x001C, 0x001D, 0x001E, 0x001F,
  916.     
  917.     0x0020, 0x0021, 0x2200, 0x0023, 0x2203, 0x0025, 0x0026, 0x220D,
  918.     0x0028, 0x0029, 0x2217, 0x002B, 0x002C, 0x2212, 0x002E, 0x002F,
  919.     
  920.     0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
  921.     0x0038, 0x0039, 0x003A, 0x003B, 0x003C, 0x003D, 0x003E, 0x003F,
  922.     
  923.     0x2245, 0x0391, 0x0392, 0x03A7, 0x0394, 0x0395, 0x03A6, 0x0393,
  924.     0x0397, 0x0399, 0x03D1, 0x039A, 0x039B, 0x039C, 0x039D, 0x039F,
  925.     
  926.     0x03A0, 0x0398, 0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03C2, 0x03A9,
  927.     0x039E, 0x03A8, 0x0396, 0x005B, 0x2234, 0x005D, 0x22A5, 0x005F,
  928.     
  929.     0x00AF, 0x03B1, 0x03B2, 0x03C7, 0x03B4, 0x03B5, 0x03C6, 0x03B3,
  930.     0x03B7, 0x03B9, 0x03D5, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BF,
  931.     
  932.     0x03C0, 0x03B8, 0x03C1, 0x03C3, 0x03C4, 0x03C5, 0x03D6, 0x03C9,
  933.     0x03BE, 0x03C8, 0x03B6, 0x007B, 0x007C, 0x007D, 0x223C, 0x003F,
  934.     
  935.     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
  936.     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
  937.     
  938.     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
  939.     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
  940.     
  941.     0x00A0, 0x03D2, 0x2032, 0x2264, 0x2044, 0x221E, 0x0192, 0x2663,
  942.     0x2666, 0x2665, 0x2660, 0x2194, 0x2190, 0x2191, 0x2192, 0x2193,
  943.     
  944.     0x00B0, 0x00B1, 0x2033, 0x2265, 0x00D7, 0x221D, 0x2202, 0x00B7,
  945.     0x00F7, 0x2260, 0x2261, 0x2248, 0x2026, 0x003F, 0x003F, 0x21B5,
  946.     
  947.     0x2135, 0x2111, 0x211C, 0x2118, 0x2297, 0x2295, 0x2205, 0x2229,
  948.     0x222A, 0x2283, 0x2287, 0x2284, 0x2282, 0x2286, 0x2208, 0x2209,
  949.     
  950.     0x2220, 0x2207, 0x00AE, 0x00A9, 0x2122, 0x220F, 0x221A, 0x22C5,
  951.     0x00AC, 0x2227, 0x2228, 0x21D4, 0x21D0, 0x21D1, 0x21D2, 0x21D3,
  952.     
  953.     0x25CA, 0x2329, 0x00AE, 0x00A9, 0x2122, 0x2211, 0x003F, 0x003F,
  954.     0x003F, 0x003F, 0x003F, 0x003F, 0x003F, 0x003F, 0x003F, 0x003F,
  955.     
  956.     0x20AC, 0x232A, 0x222B, 0x2320, 0x003F, 0x2321, 0x003F, 0x003F,
  957.     0x003F, 0x003F, 0x003F, 0x003F, 0x003F, 0x003F, 0x003F, 0x003F
  958. };
  959.  
  960. /* Function to convert from Symbol Font chars to Unicode */
  961. uint DecodeSymbolFont(uint c)
  962. {
  963.     if (c > 255)
  964.         return c;
  965.  
  966.     /* todo: add some error message */
  967.  
  968.     return Symbol2Unicode[c];
  969. }
  970.  
  971.  
  972. /* Facilitates user defined source by providing
  973. ** an entry point to marshal pointers-to-functions.
  974. ** Needed by .NET and possibly other language bindings.
  975. */
  976. Bool tidyInitSource( TidyInputSource*  source,
  977.                      void*             srcData,
  978.                      TidyGetByteFunc   gbFunc,
  979.                      TidyUngetByteFunc ugbFunc,
  980.                      TidyEOFFunc       endFunc )
  981. {
  982.   Bool status = ( source && srcData && gbFunc && ugbFunc && endFunc );
  983.  
  984.   if ( status )
  985.   {
  986.     source->sourceData = (ulong) srcData;
  987.     source->getByte    = gbFunc;
  988.     source->ungetByte  = ugbFunc;
  989.     source->eof        = endFunc;
  990.   }
  991.  
  992.   return status;
  993. }
  994.  
  995. Bool tidyInitSink( TidyOutputSink* sink,
  996.                    void*           snkData,
  997.                    TidyPutByteFunc pbFunc )
  998. {
  999.   Bool status = ( sink && snkData && pbFunc );
  1000.   if ( status )
  1001.   {
  1002.     sink->sinkData = (ulong) snkData;
  1003.     sink->putByte  = pbFunc;
  1004.   }
  1005.   return status;
  1006. }
  1007.  
  1008. /* GetByte must return a byte value in a signed
  1009. ** integer so that a negative value can signal EOF
  1010. ** without interfering w/ 0-255 legitimate byte values.
  1011. */
  1012. uint  tidyGetByte( TidyInputSource* source )
  1013. {
  1014.   int bv = source->getByte( source->sourceData );
  1015.   return (uint) bv;
  1016. }
  1017. Bool  tidyIsEOF( TidyInputSource* source )
  1018. {
  1019.   return source->eof( source->sourceData );
  1020. }
  1021. void tidyUngetByte( TidyInputSource* source, uint ch )
  1022. {
  1023.     source->ungetByte( source->sourceData, (byte) ch );
  1024. }
  1025. void tidyPutByte( TidyOutputSink* sink, uint ch )
  1026. {
  1027.     sink->putByte( sink->sinkData, (byte) ch );
  1028. }
  1029.  
  1030. uint ReadByte( StreamIn* in )
  1031. {
  1032.     return tidyGetByte( &in->source );
  1033. }
  1034. Bool IsEOF( StreamIn* in )
  1035. {
  1036.     return tidyIsEOF( &in->source );
  1037. }
  1038. void UngetByte( StreamIn* in, uint byteValue )
  1039. {
  1040.     tidyUngetByte( &in->source, byteValue );
  1041. }
  1042. void PutByte( uint byteValue, StreamOut* out )
  1043. {
  1044.     tidyPutByte( &out->sink, byteValue );
  1045. }
  1046.  
  1047. #if 0
  1048. static void UngetRawBytesToStream( StreamIn *in, byte* buf, int *count )
  1049. {
  1050.     int i;
  1051.     
  1052.     for (i = 0; i < *count; i++)
  1053.     {
  1054.         /* should never get here; testing for 0xFF, a valid char, is not a good idea */
  1055.         if ( in && IsEOF(in) )
  1056.         {
  1057.             /* fprintf(stderr,"Attempt to unget EOF in UngetRawBytesToStream\n"); */
  1058.             *count = -i;
  1059.             return;
  1060.         }
  1061.  
  1062.         in->source.ungetByte( in->source.sourceData, buf[i] );
  1063.     }
  1064. }
  1065.  
  1066. /*
  1067.    Read raw bytes from stream, return <= 0 if EOF; or if
  1068.    "unget" is true, Unget the bytes to re-synchronize the input stream
  1069.    Normally UTF-8 successor bytes are read using this routine.
  1070. */
  1071. static void ReadRawBytesFromStream( StreamIn *in, byte* buf, int *count )
  1072. {
  1073.     int ix;
  1074.     for ( ix=0; ix < *count; ++ix )
  1075.     {
  1076.         if ( in->rawPushed )
  1077.         {
  1078.             buf[ix] = in->rawBytebuf[ --in->rawBufpos ];
  1079.             if ( in->rawBufpos == 0 )
  1080.                 in->rawPushed = no;
  1081.         }
  1082.         else
  1083.         {
  1084.             if ( in->source.eof(in->source.sourceData) )
  1085.             {
  1086.                 *count = -i;
  1087.                 break;
  1088.             }
  1089.             buf[ix] = in->source.getByte( in->source.sourceData );
  1090.         }
  1091.     }
  1092. }
  1093. #endif /* 0 */
  1094.  
  1095. /* read char from stream */
  1096. uint ReadCharFromStream( StreamIn* in )
  1097. {
  1098.     uint c, n;
  1099. #ifdef TIDY_WIN32_MLANG_SUPPORT
  1100.     uint bytesRead = 0;
  1101. #endif
  1102.  
  1103.     if ( IsEOF(in) )
  1104.         return EndOfStream;
  1105.     
  1106.     c = ReadByte( in );
  1107.  
  1108.     if (c == EndOfStream)
  1109.         return c;
  1110.  
  1111. #ifndef NO_NATIVE_ISO2022_SUPPORT
  1112.     /*
  1113.        A document in ISO-2022 based encoding uses some ESC sequences
  1114.        called "designator" to switch character sets. The designators
  1115.        defined and used in ISO-2022-JP are:
  1116.  
  1117.         "ESC" + "(" + ?     for ISO646 variants
  1118.  
  1119.         "ESC" + "$" + ?     and
  1120.         "ESC" + "$" + "(" + ?   for multibyte character sets
  1121.  
  1122.        Where ? stands for a single character used to indicate the
  1123.        character set for multibyte characters.
  1124.  
  1125.        Tidy handles this by preserving the escape sequence and
  1126.        setting the top bit of each byte for non-ascii chars. This
  1127.        bit is then cleared on output. The input stream keeps track
  1128.        of the state to determine when to set/clear the bit.
  1129.     */
  1130.  
  1131.     if (in->encoding == ISO2022)
  1132.     {
  1133.         if (c == 0x1b)  /* ESC */
  1134.         {
  1135.             in->state = FSM_ESC;
  1136.             return c;
  1137.         }
  1138.  
  1139.         switch (in->state)
  1140.         {
  1141.         case FSM_ESC:
  1142.             if (c == '$')
  1143.                 in->state = FSM_ESCD;
  1144.             else if (c == '(')
  1145.                 in->state = FSM_ESCP;
  1146.             else
  1147.                 in->state = FSM_ASCII;
  1148.             break;
  1149.  
  1150.         case FSM_ESCD:
  1151.             if (c == '(')
  1152.                 in->state = FSM_ESCDP;
  1153.             else
  1154.                 in->state = FSM_NONASCII;
  1155.             break;
  1156.  
  1157.         case FSM_ESCDP:
  1158.             in->state = FSM_NONASCII;
  1159.             break;
  1160.  
  1161.         case FSM_ESCP:
  1162.             in->state = FSM_ASCII;
  1163.             break;
  1164.  
  1165.         case FSM_NONASCII:
  1166.             c |= 0x80;
  1167.             break;
  1168.         }
  1169.  
  1170.         return c;
  1171.     }
  1172. #endif /* #ifndef NO_NATIVE_ISO2022_SUPPORT */
  1173.  
  1174. #if SUPPORT_UTF16_ENCODINGS
  1175.     if ( in->encoding == UTF16LE )
  1176.     {
  1177.         uint c1 = ReadByte( in );
  1178.         if ( EndOfStream == c1 )
  1179.             return EndOfStream;
  1180.         n = (c1 << 8) + c;
  1181.         return n;
  1182.     }
  1183.  
  1184.     if ((in->encoding == UTF16) || (in->encoding == UTF16BE)) /* UTF-16 is big-endian by default */
  1185.     {
  1186.         uint c1 = ReadByte( in );
  1187.         if ( EndOfStream == c1 )
  1188.             return EndOfStream;
  1189.         n = (c << 8) + c1;
  1190.         return n;
  1191.     }
  1192. #endif
  1193.  
  1194.     if ( in->encoding == UTF8 )
  1195.     {
  1196.         /* deal with UTF-8 encoded char */
  1197.  
  1198.         int err, count = 0;
  1199.         
  1200.         /* first byte "c" is passed in separately */
  1201.         err = DecodeUTF8BytesToChar( &n, c, NULL, &in->source, &count );
  1202.         if (!err && (n == (uint)EndOfStream) && (count == 1)) /* EOF */
  1203.             return EndOfStream;
  1204.         else if (err)
  1205.         {
  1206.             /* set error position just before offending character */
  1207.             in->doc->lexer->lines = in->curline;
  1208.             in->doc->lexer->columns = in->curcol;
  1209.  
  1210.             ReportEncodingError(in->doc, INVALID_UTF8, n, no);
  1211.             n = 0xFFFD; /* replacement char */
  1212.         }
  1213.         
  1214.         return n;
  1215.     }
  1216.     
  1217. #if SUPPORT_ASIAN_ENCODINGS
  1218.     /*
  1219.        This section is suitable for any "multibyte" variable-width 
  1220.        character encoding in which a one-byte code is less than
  1221.        128, and the first byte of a two-byte code is greater or
  1222.        equal to 128. Note that Big5 and ShiftJIS fit into this
  1223.        kind, even though their second byte may be less than 128
  1224.     */
  1225.     if ((in->encoding == BIG5) || (in->encoding == SHIFTJIS))
  1226.     {
  1227.         if (c < 128)
  1228.             return c;
  1229.         else if ((in->encoding == SHIFTJIS) && (c >= 0xa1 && c <= 0xdf)) /* 461643 - fix suggested by Rick Cameron 14 Sep 01 */
  1230.         {
  1231.             /*
  1232.               Rick Cameron pointed out that for Shift_JIS, the values from
  1233.               0xa1 through 0xdf represent singe-byte characters
  1234.               (U+FF61 to U+FF9F - half-shift Katakana)
  1235.             */
  1236.             return c;
  1237.         }
  1238.         else
  1239.         {
  1240.             uint c1 = ReadByte( in );
  1241.             if ( EndOfStream == c1 )
  1242.                 return EndOfStream;
  1243.             n = (c << 8) + c1;
  1244.             return n;
  1245.         }
  1246.     }
  1247. #endif
  1248.  
  1249. #ifdef TIDY_WIN32_MLANG_SUPPORT
  1250.     else if (in->encoding > WIN32MLANG)
  1251.     {
  1252.         assert( in->mlang != 0 );
  1253.         return Win32MLangGetChar((byte)c, in, &bytesRead);
  1254.     }
  1255. #endif
  1256.  
  1257.     else
  1258.         n = c;
  1259.         
  1260.     return n;
  1261. }
  1262.  
  1263. /* Output a Byte Order Mark if required */
  1264. void outBOM( StreamOut *out )
  1265. {
  1266.     if ( out->encoding == UTF8
  1267. #if SUPPORT_UTF16_ENCODINGS
  1268.          || out->encoding == UTF16LE
  1269.          || out->encoding == UTF16BE
  1270.          || out->encoding == UTF16
  1271. #endif
  1272.        )
  1273.     {
  1274.         /* this will take care of encoding the BOM correctly */
  1275.         WriteChar( UNICODE_BOM, out );
  1276.     }
  1277. }
  1278.  
  1279. /* this is in intermediate fix for various problems in the */
  1280. /* long term code and data in charsets.c should be used    */
  1281. static struct _enc2iana
  1282. {
  1283.     uint id;
  1284.     ctmbstr name;
  1285. } enc2iana[] =
  1286. {
  1287.   { ASCII,    "us-ascii"     },
  1288.   { LATIN0,   "iso-8859-15"  },
  1289.   { LATIN1,   "iso-8859-1"   },
  1290.   { UTF8,     "utf-8"        },
  1291.   { MACROMAN, "macintosh"    },
  1292.   { WIN1252,  "windows-1252" },
  1293.   { IBM858,   "ibm00858"     },
  1294. #if SUPPORT_UTF16_ENCODINGS
  1295.   { UTF16LE,  "utf-16"       },
  1296.   { UTF16BE,  "utf-16"       },
  1297.   { UTF16,    "utf-16"       },
  1298. #endif
  1299. #if SUPPORT_ASIAN_ENCODINGS
  1300.   { BIG5,     "big5"         },
  1301.   { SHIFTJIS, "shift_jis"    },
  1302. #endif
  1303. #ifndef NO_NATIVE_ISO2022_SUPPORT
  1304.   { ISO2022,  NULL           },
  1305. #endif
  1306.   { RAW,      NULL           }
  1307. };
  1308.  
  1309. ctmbstr GetEncodingNameFromTidyId(uint id)
  1310. {
  1311.     uint i;
  1312.  
  1313.     for (i = 0; enc2iana[i].name; ++i)
  1314.         if (enc2iana[i].id == id)
  1315.             return enc2iana[i].name;
  1316.  
  1317.     return NULL;
  1318. }
  1319.